home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / System 7.0 Samples / AEObject-Edition1.0.2 Sample / Subscribe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-18  |  58.3 KB  |  1,249 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. *
  3. *  Apple Developer Technical Support
  4. *
  5. *  Edition subscribing routines
  6. *
  7. *  Program:    AEObject-Edition Sample
  8. *  File:       Subscribe.c -   C Source
  9. *
  10. *  by:         C.K. Haun <TR>
  11. *
  12. *  Copyright © 1990-1992 Apple Computer, Inc.
  13. *  All rights reserved.
  14. *
  15. *------------------------------------------------------------------------------
  16. * This file handles the Subscribe section of the program.  It also handles some of 
  17. * the common use routines, like the section options dialog.
  18. *----------------------------------------------------------------------------*/
  19.  
  20. #define __SUBSCRIBE__
  21.  
  22. #pragma segment Subscribe
  23.  
  24. #include "Sampdefines.h"
  25.  
  26. /* this point tells EM to center our expanded box, if we're using that feature */
  27. Point expPoint = 
  28. {
  29.     -1, -1
  30. };
  31.  
  32.  
  33.  
  34.  
  35. /* DoSubscribe presents the user with the Subscriber dialog, and allows the user to */
  36. /* subscribe to a PICT type edition, anywhere, anytime.  It also stores the */
  37. /* section handle returned in the window data structure for the current window */
  38. /* You can only subscribe to TEXT if you have a text box open in the current window.  */
  39. /* Optionally, of course, you can put in your own conversion of the TEXT to a PICT and */
  40. /* subscribe to that as such, same as you would with clipboard types. */
  41.  
  42. void DoSubscribe(void)
  43. {
  44.     OSErr myErr;
  45.     SectionHandle secHandle;
  46.     windowCHandle shortName;
  47.     NewSubscriberReply GetSub;
  48.     shortName = (windowCHandle)GetWRefCon(FrontWindow());       /* get our struct */
  49.     GetSub.formatsMask = kPICTformatMask;                   /* tell the dialog we only want PICT type editions */
  50.     if ((*shortName)->boxHandle != nil)                     /* is there a text box already? */
  51.         GetSub.formatsMask += kTEXTformatMask;
  52.     /* GetLastEditionContainerUsed gives you either the last edition container used  */
  53.     /* (either pub or sub, since they are the same to the Edition Manager) or if there */
  54.     /* was not a previous container, it fills it with a default container. */
  55.     GetLastEditionContainerUsed(&GetSub.container);
  56.     /* Now ask the user to select an edition to subscribe to */
  57.     if (!gExpanded)
  58.         myErr = NewSubscriberDialog(&GetSub);
  59.     else
  60.     {
  61.         ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
  62.         ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
  63.         myErr = NewSubscriberExpDialog(&GetSub, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
  64.         DisposeRoutineDescriptor(mfUPP);
  65.         DisposeRoutineDescriptor(dhUPP);
  66.     }
  67.     
  68.     if (myErr != noErr) {                                   /* bail on fail */
  69.         ShowMe("\pNewSubscriberDialog", myErr, __LINE__);
  70.         return;
  71.     }
  72.     if (GetSub.canceled)                                    /* did they cancel the dialog? */
  73.         return;
  74.     HLock((Handle)shortName);
  75.     /* Now create a new section record for the container the user picked.  In other words, the */
  76.     /* Edition manager keeps track of things by the container, and will give you a section */
  77.     /* record that refers to it for you to keep track with.  */
  78.     /* ••• NOTE: Whenever the Edition Manager gives you memory (like the section handle) */
  79.     /* it came out of your heap, and YOU are responsible for disposing of it when you are */
  80.     /* completely done (and have UnRegistered) the section.  If you're not careful about this */
  81.     /* then you'll get creeping memory loss.  */
  82.     /* Now see if the window has ever been saved.  If so, we can store a reference to */
  83.     /* the file in the section */
  84.     if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
  85.         myErr = NewSection(&GetSub.container, nil, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic, &secHandle);
  86.     } else {
  87.         /* if the file has been saved once, then we can store a reference to the 'parent' file */
  88.         /* in the edition */
  89.         FSSpec tempSpec;
  90.         Boolean myWasChanged;
  91.         myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
  92.         myErr = NewSection(&GetSub.container, &tempSpec, stSubscriber, (*shortName)->windowID + gSectionID, sumAutomatic,
  93.                            &secHandle);
  94.     }
  95.     if (myErr != noErr) {
  96.         ShowMe("\pNewSection", myErr, __LINE__);
  97.         return;
  98.     }
  99.     /* section successfully gotten.  Add it to the current window section list please */
  100.     /* Handle this in whatever way is appropriate for your application, of course.  */
  101.     /* The main point to remember is that you _must_ keep track of the section handles, */
  102.     /* they are your method (only method) for comunication between your application */
  103.     /* and the Edition Manager, you will be passing sections to the EM, and it will be */
  104.     /* passing them back to you. */
  105.     gSectionID++;                                           /* increment our unique ID */
  106.     StoreSubscriber(shortName, secHandle, nil, nil);
  107.     HUnlock((Handle)shortName);
  108. }
  109.  
  110. /* end DoSubscribe */
  111. /* DoOptions handles the SectionOptions menu selection.  The handle passed */
  112. /* (inSection) is a subscriber OR publisher section, the Edition Manager will figure */
  113. /* out what dialog to display by looking at the section record */
  114. /* ••• BE CAREFUL with the section  handle you pass to the options dialog (or anywhere, for that matter) */
  115. /* A section that has not been registered, or a section containing a bad alias handle, will */
  116. /* cause the options dialog to blow up in unusual and fun ways */
  117. /* This call also includes the expanded section options dialog box with one */
  118. /* extra item, to show how it's used. */
  119. void DoOptions(SectionHandle inSection)
  120. {
  121.     OSErr myErr;
  122.     SectionOptionsReply oreply;
  123.     Boolean subExpansion;
  124.     
  125.     oreply.sectionH = inSection;                            /* put the section passed in the reply record */
  126.     if ((*inSection)->kind == stSubscriber)
  127.         subExpansion = true;
  128.     else
  129.         subExpansion = false;
  130.     myErr = IsRegisteredSection(inSection);
  131.     if (myErr != noErr) {
  132.         ShowMe("\p Bad Section ", myErr, __LINE__);
  133.         return;
  134.     }
  135.     if (subExpansion) {
  136.         ExpDlgHookUPP dhUPP = NewExpDlgHookProc(SubExpOptHook);
  137.         ExpModalFilterUPP mfUPP = NewExpModalFilterProc(SubExpOptFilter);
  138.         myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedSubDITL, dhUPP, mfUPP, nil);
  139.         DisposeRoutineDescriptor(dhUPP);
  140.         DisposeRoutineDescriptor(mfUPP);
  141.     } else {
  142.         if (!gExpanded)
  143.             myErr = SectionOptionsDialog(&oreply);          /* run the dialog */
  144.         else
  145.         {
  146.             ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
  147.             ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
  148.             myErr = SectionOptionsExpDialog(&oreply, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
  149.             DisposeRoutineDescriptor(dhUPP);
  150.             DisposeRoutineDescriptor(mfUPP);
  151.         }
  152.     }
  153.     if (myErr != noErr) {
  154.         ShowMe("\pSection Options", myErr, __LINE__);
  155.         return;
  156.     }
  157.     if (oreply.canceled)                                    /* if user canceled */
  158.         return;
  159.     if (oreply.action == sectionReadMsgID) {
  160.         /* if the user clicked 'Get Edition Now' you'll call your section read routine, the same */
  161.         /* one that gets called on a sect read AppleEvent */
  162.         MyReadSection(inSection);
  163.     } else {
  164.         if (oreply.action == sectionWriteMsgID) {
  165.             /* if the user clicked 'Send Edition Now' you'll call your section write routine, the same */
  166.             /* one that gets called on a sect writ AppleEvent */
  167.             MyUpdateEdition(inSection);
  168.         } else {
  169.             if (oreply.action == 'goto') {  /* why isn't there a constant fo this? */
  170.                 /* this is the sect scrl (section scroll) event from the dialog */
  171.                 /* the dialog has already taken the action for you, that's it's job */
  172.             } else {
  173.                 if (oreply.action == emCancelSectionDialogRefCon) {
  174.                     /* This is for canceling a section, either pub or sub, you have to make the */
  175.                     /* choice based on what the section is */
  176.                     SectionType tempST;
  177.                     HLock((Handle)inSection);
  178.                     tempST = (*inSection)->kind;            /* what kinda thing is this? */
  179.                     HUnlock((Handle)inSection);
  180.                     
  181.                     MyCancelSection(inSection, FindSection(inSection));
  182.                 }
  183.             }
  184.         }
  185.     }
  186. }
  187.  
  188. /* end DoOptions */
  189.  
  190. /* AEReadSectionHandler is the handler I installed in the AppleEvent manager list for */
  191. /* AppleEvents of the type 'sect' 'read'.  What this means is that whenever I get a */
  192. /* high level event of the type 'sect' 'read' this routine will be dispatched to when I */
  193. /* call AEProcessAppleEvent (in AppleEventM.c).   This is where the actual section data */
  194. /* gets read in, when the Edition Manager tells you the edition is ready to read */
  195. pascal OSErr AEReadSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  196. {
  197. #pragma unused (reply,refIn)
  198.     SectionHandle theSection;
  199.     OSErr myErr;
  200.     
  201.     myErr = GetSectionHandleFromEvent(messagein, &theSection);      /* in AppleEventM.c */
  202.     if (myErr) {
  203.         ShowMe("\pGetSectionHandleFromEvent", myErr, __LINE__);
  204.         return(myErr);
  205.     }
  206.     /* This next step is very important.  Unexpected things can happen to you, */
  207.     /* a section could disappear between the time an event gets posted and when it */
  208.     /* finally gets to your application (particularly since AppleEvents are the lowest in */
  209.     /* the event hierarchy), the section may have been canceled, deleted, disk off-line, or */
  210.     /* whatever.  You must make a current check with the EM to see if the section that */
  211.     /* you are supposed to read. */
  212.     myErr = IsRegisteredSection((SectionHandle)theSection);
  213.     if (myErr) {
  214.         ShowMe("\pRead IsRegisteredSection", myErr, __LINE__);
  215.         return(myErr);
  216.     }
  217.     /* It is a valid section.  Jump to my routine that opens and reads it */
  218.     MyReadSection(theSection);
  219. }
  220.  
  221. /* end AEReadSectionHandler */
  222.  
  223. /* MyReadSection opens and reads the edition data into my window data structure. */
  224. OSErr MyReadSection(SectionHandle theSection)
  225. {
  226.     OSErr myErr;
  227.     EditionRefNum sRefNum=0;
  228.     Size dataSize;
  229.     Boolean existed = false;                                /* for setting the display rect */
  230.     /* open the edition and get a ref number */
  231.     SpinCursor();
  232.     myErr = OpenEdition(theSection, &sRefNum);
  233.     if (myErr) {
  234.         if(sRefNum)CloseEdition(sRefNum,true);
  235.         ShowMe("\pOpenEdition", myErr, __LINE__);
  236.         return(myErr);
  237.         
  238.     }
  239.     /* Here we are double-checking the edition.  I'm first checking for PICT data, */
  240.     /* and as a handy side effect, it gives us the size of the data (returned in my */
  241.     /* variable dataSize) for us to use when we read it later */
  242.     
  243.     
  244.     if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))) {
  245.         /* It does have a pict, read it in */
  246.         register  jj;                                    /* loop vars for window search */
  247.         long subIDtofind;
  248.         
  249.         /*  There is already a handle allocated for this picture in the window structure. 
  250.         *   Find it, resize it (since the edition size could have changed) and fill it.
  251.         *       Keep in mind that the section read may happen for a window which is not 
  252.         *       frontmost, so we need to search all the windows to find the ID */
  253.         WindowPtr tempPort;
  254.         Boolean secFound = false;
  255.         SectionHandle *tempPtr;
  256.         SectionRecord *tempRecord;
  257.         Handle tempHandle;
  258.         WindowPtr tempNextWindow;
  259.         Rect *tempRect;
  260.         Rect holdRect;
  261.         SpinCursor();
  262.         HLock((Handle)theSection);
  263.         subIDtofind = (*theSection)->sectionID;             /* what ID are we reading?  */
  264.         /* check to see if this is the clipboard's section.  If so, let the clipboard */
  265.         /* handle it */
  266.         if ((subIDtofind == (*gClipSection)->sectionID) && (gClipSection != nil)){
  267.             return(ReadClipSection(dataSize, sRefNum));
  268.             }
  269.         GetPort(&tempPort);                                 /* save the current port */
  270.         /* search window list now */
  271.         tempNextWindow = (WindowPtr)LMGetWindowList();                         /* start at the beginning of the chain */
  272.         while (tempNextWindow) {
  273.             SpinCursor();
  274.             if (((WindowPeek)tempNextWindow)->windowKind == kDocumentWindow) {
  275.                 windowCHandle tempWC;
  276.                 /* do housekeeping to get to the section handle list */
  277.                 tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
  278.                 HLock((Handle)tempWC);
  279.                 tempHandle = (*tempWC)->subs;               /* handle containing SectionHandles */
  280.                 HLock(tempHandle);
  281.                 tempPtr = (SectionHandle *)*tempHandle;
  282.                 /* Loop through all our sections until we find this edition */
  283.                 for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
  284.                     Handle *newTemp;
  285.                     SpinCursor();
  286.                     HLock((Handle)*tempPtr);
  287.                     tempRecord = *(*tempPtr);
  288.                     if (tempRecord->sectionID == subIDtofind) {
  289.                         /* found the section belonging to this read. */
  290.                         /* can't break, since it is conceiveable that the user has more that one subscription in this document */
  291.                         SetPort(tempNextWindow);            /* set the port to the window we found the section in */
  292.                         HLock((*tempWC)->subDataHandle);
  293.                         newTemp = (Handle *)*((*tempWC)->subDataHandle);
  294.                         newTemp += jj;
  295.                         /* if the dataSize returned was -1 then the size was unknown when opened.  */
  296.                         /* in this case, this should only happen with our special opener.  */
  297.                         /* So, if it is -1, then we'll have to handle the read */
  298.                         /* in a series of steps to get the right amount of data */
  299.                         /* For now, I'll leave that out until I put in a custom */
  300.                         /* opener. Watch this space */
  301.                         if (dataSize != -1) {
  302.                             HUnlock(*newTemp);
  303.                             MySetHandleSize(*newTemp, dataSize);
  304.                             HLock(*newTemp);
  305.                         }
  306.                         SpinCursor();
  307.                         /* read the pict in */
  308.                         myErr = MyReadEditionData(**newTemp, kGenericPICTWord, sRefNum, &dataSize);
  309.                         /* ••••• NOTE: After much discussion with our Human Interface folks and the */
  310.                         /* Edition Manager engineer, we've decided that the interface guidelines */
  311.                         /* for editions will say that reading a subscription does _not_ dirty */
  312.                         /* a document.  A lot of soul-searching went on to make this decision, and */
  313.                         /* we decided this way primarily to keep the user from getting confused.  */
  314.                         /* Editions should be as transparent and automatic as possible, and reminding */
  315.                         /* the user that an edition is a 'special' thing that they have to do */
  316.                         /* unusual things with to make work right will remove some of that */
  317.                         /* automation.  Of course, the 'cached' version of the subscription that */
  318.                         /* you save with the document should be updated when the subscription changes */
  319.                         /* So, the following line was commented out. */
  320.                         /* (*tempWC)->windowDirty = true;  */
  321.                         /* mark window dirty on every read */
  322.                         holdRect = (*(PicHandle)(*newTemp))->picFrame;
  323.                         HUnlock(*newTemp);
  324.                         /* put the picture in the corner, if it didn't exist.  If it did, adjust the rect as
  325.                         *   required */
  326.                         HLock((*tempWC)->subRects);
  327.                         newTemp = (Handle *)*((*tempWC)->subRects);
  328.                         newTemp += jj;
  329.                         /* if the handle is the size of a rect, I've seen this edition before */
  330.                         if (GetHandleSize(*newTemp) == sizeof(Rect)) {
  331.                             existed = true;                 /* it's already been made */
  332.                         } else {
  333.                             HUnlock(*newTemp);
  334.                             MySetHandleSize(*newTemp, sizeof(Rect));        /* new subscription */
  335.                         }
  336.                         HLock(*newTemp);
  337.                         tempRect = (Rect *)*(*newTemp);
  338.                         if (!existed) {
  339.                             tempRect->top = tempRect->left = 0;
  340.                             tempRect->bottom = holdRect.bottom - holdRect.top;
  341.                             tempRect->right = holdRect.right - holdRect.left;
  342.                         } else {
  343.                             InvalRect(tempRect);            /* refresh the old image if the thing was resized */
  344.                             /*          tempRect->bottom = tempRect->top + (holdRect.bottom - holdRect.top);
  345.                             tempRect->right = tempRect->left + (holdRect.right - holdRect.left);
  346.                             */
  347.                         }
  348.                         InvalRect(tempRect);
  349.                         HUnlock(*newTemp);
  350.                         HUnlock((Handle)*tempPtr);
  351.                         
  352.                     } else {
  353.                         HUnlock((Handle)*tempPtr);
  354.                         tempPtr += 1;
  355.                     }
  356.                 }                                           /* section handle loop jj */
  357.  
  358.                 HUnlock(tempHandle);
  359.                 HUnlock((Handle)tempWC);
  360.                 /* ••• NOTE: You'll notice that there is no break or exit from this section searching loop */
  361.                 /* Why?  Because there may be many subscribers to the same edition.  The user may */
  362.                 /* have multiple subscribtions in the same window, or in any of his or her windows. */
  363.                 /* Don't assume that there is only one subscriber (unless you require it, which may be */
  364.                 /* reasonable for a single document but _not_ for a multi-document application), run */
  365.                 /* your whole list each time to be certain everything gets refreshed */
  366.             }                                               /* if document */
  367.             SpinCursor();
  368.             tempNextWindow = (WindowPtr)((WindowPeek)tempNextWindow)->nextWindow;
  369.         }                                                   /* window loop qq */
  370.         SetPort(tempPort);                                  /* reset the port to what it was when we entered */
  371.     } else {
  372.         if (noErr == (myErr = EditionHasFormat(sRefNum, kGenericTEXTWord, &dataSize))) {
  373.             WindowPtr theWindow;
  374.             windowCHandle tempWC;
  375.             TEHandle tempTEH;
  376.             mySectionDataHandle theTES;
  377.             long tempStart, tempEnd;
  378.             SpinCursor();
  379.             /* it's a text subscription.  That means we search in the text path, and also need */
  380.             /* to update the TEHandle for the window this goes with */
  381.             theWindow = FindSection(theSection);
  382.             theTES = TextSectionFromSecHandle(theSection);
  383.             HLock((Handle)theTES);
  384.             tempWC = (windowCHandle)GetWRefCon(theWindow);
  385.             tempTEH = (*tempWC)->boxHandle;
  386.             /* save the current TE selection range so that the user is returned to the */
  387.             /* place he or she was before we did the reading, so the text doesn't jump */
  388.             /* around all loony on them */
  389.             tempStart = (*tempTEH)->selStart;
  390.             tempEnd = (*tempTEH)->selEnd;
  391.             
  392.             /* first thing we need to do is remove whatever the current sub data in our */
  393.             /* TE Record is.  if there is any, o'course */
  394.             if ((*theTES)->startChar != (*theTES)->endChar) {
  395.                 TESetSelect((*theTES)->startChar, (*theTES)->endChar, (TEHandle)tempTEH);
  396.                 TEDelete(tempTEH);
  397.             }
  398.             SetHandleSize((*theTES)->additionalData, dataSize);
  399.             HLock((*theTES)->additionalData);
  400.             MyReadEditionData(*(*theTES)->additionalData, kGenericTEXTWord, sRefNum, &dataSize);
  401.             SpinCursor();
  402.             /* that gives us the text.  Now we need to adjust our endpoint */
  403.             (*theTES)->endChar = ((*theTES)->startChar) + dataSize;
  404.             /* set insertion point to where we want to be */
  405.             TESetSelect((*theTES)->startChar, (*theTES)->startChar, tempTEH);
  406.             TEInsert(*(*theTES)->additionalData, dataSize, tempTEH);
  407.             HUnlock((*theTES)->additionalData);
  408.             HUnlock((Handle)theTES);
  409.             /* reset insertion point to what it once was */
  410.             TESetSelect(tempStart, tempEnd, tempTEH);
  411.         }
  412.     }
  413. }
  414.  
  415. /* end MyReadSection */
  416.  
  417. OSErr MyReadEditionData(Ptr readinPtr, DescType typeToGet, EditionRefNum readRef, Size *howMuch)
  418. {
  419.     OSErr myErr;
  420.     if (myErr = ReadEdition(readRef, typeToGet, readinPtr, howMuch))
  421.         CloseEdition(readRef, false);
  422.     else
  423.         CloseEdition(readRef, true);
  424.         if(myErr)ShowMe("\p reading error",myErr,0);
  425.     return(myErr);
  426. }
  427.  
  428. /*  HandleSectionSave handles saving and closing of subscribers for */
  429. /*       a document.  The Boolean flags tell this function wheither to write */
  430. /*       ouut the data [on save or save/close] and weither to UnRegister */
  431. /*       the sections [on close]. */
  432. /*       The resource fork is open on entry. */
  433. /* theWind is locked on entry */
  434. void HandleSectionSave(windowCHandle theWind, Boolean writeEm, Boolean dereg, FSSpec *theSpec)
  435. {
  436.     SectionHandle *theSections;
  437.     Handle *newTemp;
  438.     SectionRecord secRec;
  439.     Handle tempHandle;
  440.     Rect *tempRectPtr;
  441.     register qq;
  442.     OSErr myErr;
  443.     if ((*theWind)->numSubs) {
  444.         Handle *tempPictPtr;
  445.         HLock((*theWind)->subs);
  446.         theSections = (SectionHandle *)*(*theWind)->subs;
  447.         /* and display rectangles */
  448.         HLock((*theWind)->subRects);
  449.         HLock((*theWind)->subDataHandle);
  450.         newTemp = (Handle *)*((*theWind)->subRects);
  451.         tempPictPtr = (Handle *)*((*theWind)->subDataHandle);
  452.         /* loop through the sections */
  453.         for (qq = 0; qq < (*theWind)->numSubs; qq++) {
  454.             SpinCursor();
  455.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  456.             myErr = AssociateSection(*theSections, theSpec);
  457.             if (myErr)
  458.                 ShowMe("\p Assocate", myErr, __LINE__);
  459.             
  460.             
  461.             
  462.             /* write the section handle out... */
  463.             if (writeEm) {
  464.                 tempHandle = (Handle)*theSections;
  465.                 HandToHand(&tempHandle);
  466.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  467.                 secRec = *(*(*theSections));                /* just for easier display below */
  468.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  469.                 /* now do the same with the alias record please */
  470.                 tempHandle = (Handle)secRec.alias;
  471.                 HandToHand(&tempHandle);
  472.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  473.                 HUnlock((Handle)*theSections);
  474.                 /* save off the display rect for this sub */
  475.                 tempHandle = *newTemp;
  476.                 HandToHand(&tempHandle);
  477.                 AddResource(tempHandle, kRECTType, secRec.sectionID, "");
  478.                 /* and save out the picture data, so we don't need to immediatly do a */
  479.                 /* section read when the file is opened */
  480.                 tempHandle = *tempPictPtr;
  481.                 HandToHand(&tempHandle);
  482.                 AddResource(tempHandle, kGenericPICTWord, secRec.sectionID, "");
  483.             }                                               /* writeEm if */
  484.             
  485.             if (dereg) {
  486.                 UnRegisterSection(*theSections);
  487.                 /* and dispose of the alias handle */
  488.                 DisposeHandle((Handle)*(*(*theSections))->alias);
  489.                 /* and the section handle */
  490.                 DisposeHandle((Handle)*theSections);
  491.                 /* and the rectangle handle */
  492.                 DisposeHandle((Handle)*newTemp);
  493.                 /* picture handle disposed in closewindow */
  494.             }
  495.             theSections += 1;                               /* go to next section handle please */
  496.             newTemp += 1;                                   /* and next rectangle */
  497.         }
  498.         HUnlock((*theWind)->subRects);
  499.         HUnlock((*theWind)->subs);
  500.     }                                                       /* end subscriber save section */
  501.     /* now do the same thing for our publishers please */
  502.     /* Of course, here you'll also write the data if pumAutomatic is set */
  503.     
  504.     if ((*theWind)->numPubs) {
  505.         SpinCursor();
  506.         HLock((*theWind)->pubs);
  507.         theSections = (SectionHandle *)*(*theWind)->pubs;
  508.         /* and display rectangles */
  509.         HLock((*theWind)->pubRects);
  510.         tempRectPtr = (Rect *)*((*theWind)->pubRects);
  511.         
  512.         /* loop through the sections */
  513.         for (qq = 0; qq < (*theWind)->numPubs; qq++) {
  514.             SpinCursor();
  515.             /* first update (or create, if needed, the Ed Manger will know) the alias */
  516.             AssociateSection(*theSections, theSpec);
  517.             /* write the section handle out... */
  518.             if (writeEm) {
  519.                 tempHandle = (Handle)*theSections;
  520.                 HandToHand(&tempHandle);
  521.                 HLock((Handle)*theSections);                /* lock down the original section so we can work with it */
  522.                 secRec = *(*(*theSections));                /* just for easier display below */
  523.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  524.                 SpinCursor();
  525.                 /* now do the same with the alias record please */
  526.                 tempHandle = (Handle)secRec.alias;
  527.                 HandToHand(&tempHandle);
  528.                 
  529.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  530.                 SpinCursor();                
  531.                 HUnlock((Handle)*theSections);
  532.                 /* save off the display rect for this pub */
  533.                 
  534.                 tempHandle = NewHandle(sizeof(Rect));
  535.                 PtrToHand((Ptr)tempRectPtr, &tempHandle, sizeof(Rect));
  536.                 HandToHand(&tempHandle);
  537.                 AddResource(tempHandle, kRECTType, secRec.sectionID, "");
  538.                 SpinCursor();                
  539.                 if (secRec.mode == pumOnSave) {
  540.                     MyUpdateEdition(*theSections);
  541.                     /* and indicate that this was saved with a document */
  542.                     (*(*theSections))->refCon |= kSavedOnce;        /* OR in our saved flag with type */
  543.                 }
  544.             }                                               /* writeEm if for pubs */
  545.             
  546.             if (dereg) {
  547.                 UnRegisterSection(*theSections);
  548.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  549.                 /* then we'll delete it.  */
  550.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved) {
  551.                     OSErr myErr;
  552.                     FSSpec deleteSpec;
  553.                     Boolean myWasChanged;
  554.                     ResolveAlias(nil, ((*(*theSections))->alias), &deleteSpec, &myWasChanged);
  555.                     SpinCursor();                    
  556.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  557.                         ShowMe("\pDelete Editon", myErr, __LINE__);
  558.                     }
  559.                 }
  560.                 
  561.                 /* and dispose of the alias handle */
  562.                 DisposeHandle((Handle)*(*(*theSections))->alias);
  563.                 /* and the section handle */
  564.                 DisposeHandle((Handle)*theSections);
  565.                 
  566.             }
  567.             theSections += 1;                               /* go to next section handle please */
  568.             tempRectPtr += 1;                               /* and next rectangle */
  569.         }
  570.         HUnlock((*theWind)->pubRects);
  571.         HUnlock((*theWind)->pubs);
  572.     }
  573.     /* now save off any text sections in this document */
  574.     if ((*theWind)->textSections) {
  575.         mySectionDataHandle tempTS = (*theWind)->textSections;
  576.         do {
  577.             SpinCursor();
  578.             tempHandle = (Handle)(*tempTS)->theSection;
  579.             /* make sure the text is the latest */
  580.             RePackText(tempTS, (*theWind)->boxHandle);
  581.             AssociateSection((SectionHandle)tempHandle, theSpec);
  582.             
  583.             if (writeEm) {
  584.                 HandToHand(&tempHandle);
  585.                 myErr = MemError();
  586.                 if (myErr)
  587.                     ShowMe("\p memerr", myErr, __LINE__);
  588.                 HLock(tempHandle);                          /* lock down the original section so we can work with it */
  589.                 secRec = *(*(SectionHandle)tempHandle);     /* just for easier display below */
  590.                 AddResource(tempHandle, rSectionType, secRec.sectionID, "");
  591.                 SpinCursor();
  592.                 /* save the alias */
  593.                 tempHandle = (Handle)secRec.alias;
  594.                 HandToHand(&tempHandle);
  595.                 AddResource(tempHandle, rAliasType, secRec.sectionID, "");
  596.                 SpinCursor();
  597.                 /* now save a copy of my whole text record */
  598.                 
  599.                 tempHandle = (Handle)tempTS;
  600.                 HandToHand(&tempHandle);
  601.                 /* use the same ID number as the section, make things easy */
  602.                 /* zap any forward link in this, so StoreSection doesn't get */
  603.                 /* confused when the section is read back in */
  604.                 (*(mySectionDataHandle)tempHandle)->nextSection = nil;
  605.                 (*(mySectionDataHandle)tempHandle)->additionalData = nil;
  606.                 (*(mySectionDataHandle)tempHandle)->theSection = nil;
  607.                 AddResource(tempHandle, rMyTextRecordType, secRec.sectionID, "");
  608.                 
  609.                 /* and finally, the associated text */
  610.                 tempHandle = (*tempTS)->additionalData;
  611.                 HandToHand(&tempHandle);
  612.                 AddResource(tempHandle, rMyTextBlock, secRec.sectionID, "");
  613.                 SpinCursor();
  614.                 if (secRec.kind == stPublisher && secRec.mode == pumOnSave) {
  615.                     MyUpdateEdition((*tempTS)->theSection);
  616.                     /* and indicate that this was saved with a document */
  617.                     (*(*tempTS)->theSection)->refCon |= kSavedOnce;     /* OR in our saved flag with type */
  618.                 }
  619.             }                                               /* text writeem if */
  620.             
  621.             if (dereg) {
  622.                 UnRegisterSection((SectionHandle)tempHandle);
  623.                 /* first see if this publisher has ever been saved with a document.  If it hasn't */
  624.                 /* then we'll delete it.  */
  625.                 if (((*(*theSections))->refCon & 0xf0) == kNeverSaved && (*(*theSections))->kind == stPublisher) {
  626.                     OSErr myErr;
  627.                     FSSpec deleteSpec;
  628.                     Boolean myWasChanged;
  629.                     ResolveAlias(nil, (*(SectionHandle)tempHandle)->alias, &deleteSpec, &myWasChanged);
  630.                     if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  631.                         ShowMe("\pSection Save Delete Editon", myErr, __LINE__);
  632.                     }
  633.                 }
  634.                 
  635.                 /* and dispose of the alias handle */
  636.                 DisposeHandle((Handle)(*(SectionHandle)tempHandle)->alias);
  637.                 /* and the section handle */
  638.                 DisposeHandle((Handle)tempHandle);
  639.                 
  640.             }
  641.             tempTS = (*tempTS)->nextSection;
  642.         }
  643.                 while (tempTS);
  644.         
  645.     }
  646. }
  647.  
  648. /* MyCancelSection cancels this section.  It removes  */
  649. /*  the section info from our window structure, and also de-registers the */
  650. /* section with (from) the Edition Manager.  If it's a publisher, it also  */
  651. /* deletes the edition file  */
  652.  
  653. void MyCancelSection(SectionHandle inSection, WindowPtr theWindow)
  654. {
  655.     OSErr myErr;
  656.     windowCHandle shortName;
  657.     SectionHandle *tempPtr;
  658.     Rect *tempRectPtr;
  659.     register qq;
  660.     FSSpec deleteSpec;
  661.     Boolean myWasChanged;
  662.     shortName = (windowCHandle)GetWRefCon(theWindow);
  663.     HLock((Handle)shortName);
  664.     
  665.     /* first thing to do is deregister the thing */
  666.     UnRegisterSection(inSection);
  667.     if ((*inSection)->kind == stPublisher) {                /* only delete publishers */
  668.         ResolveAlias(nil, ((*inSection)->alias), &deleteSpec, &myWasChanged);
  669.         if (myErr = DeleteEditionContainerFile(&deleteSpec)) {
  670.             ShowMe("\pCancel Delete Editon", myErr, __LINE__);
  671.         }
  672.     }
  673.     /* get rid of the alias handle for it */
  674.     DisposeHandle((Handle)(*inSection)->alias);
  675.     if ((*inSection)->kind == stPublisher) {
  676.         HLock((*shortName)->pubs);                          /* lock down my list of section handles */
  677.         tempPtr = (SectionHandle *)*(*shortName)->pubs;
  678.         for (qq = 0; qq < (*shortName)->numPubs; qq++) {
  679.             HLock((Handle)*tempPtr);
  680.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  681.                 DisposeHandle((Handle)inSection);
  682.                 DisposeHandle((Handle)(*(*tempPtr))->alias);
  683.                 DisposeHandle((Handle)*tempPtr);
  684.                 HLock((*shortName)->pubRects);
  685.                 tempRectPtr = (Rect *)*((*shortName)->pubRects);
  686.                 tempRectPtr += qq;
  687.                 if (qq != (*shortName)->numPubs) {
  688.                     register ii;                            /* need to move information down */
  689.                     for (ii = qq; ii < ((*shortName)->numPubs) - 1; ii++) {
  690.                         *tempPtr = *(tempPtr + 1);
  691.                         *tempRectPtr = *(tempRectPtr + 1);
  692.                         tempPtr += 1;
  693.                         tempRectPtr += 1;
  694.                     }
  695.                 }
  696.                 (*shortName)->numPubs--;
  697.                 HUnlock((*shortName)->pubs);
  698.                 MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) - sizeof(Handle));
  699.                 HUnlock((*shortName)->pubRects);
  700.                 MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) - sizeof(Rect)));
  701.                 
  702.             }
  703.         }
  704.     } else {                                                /* it's a subscriber */
  705.         
  706.         HLock((*shortName)->subs);                          /* lock down my list of section handles */
  707.         tempPtr = (SectionHandle *)*(*shortName)->subs;
  708.         for (qq = 0; qq < (*shortName)->numSubs; qq++) {
  709.             
  710.             HLock((Handle)*tempPtr);
  711.             if ((*inSection)->sectionID == (*(*tempPtr))->sectionID) {
  712.                 SectionHandle removeSection;
  713.                 Handle *tempRectHand;
  714.                 Handle *tempPicHand;
  715.                 Handle *tempPicHand2;
  716.                 removeSection = (*tempPtr);
  717.                 HLock((Handle)removeSection);
  718.                 /* When the user cancels a subscription, you do NOT want to delete the */
  719.                 /* current subscription data (the picture) at this time.  Since the data should be */
  720.                 /* selectable in the document they are working on (text in a text doc, pic in a */
  721.                 /* pic doc, etc) they keep the last subscription data, and delete it */
  722.                 /* seperatly if they'd like */
  723.                 HLock((*shortName)->subRects);
  724.                 HLock((*shortName)->subDataHandle);
  725.                 tempRectHand = (Handle *)*((*shortName)->subRects);
  726.                 tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  727.                 tempRectHand += qq;
  728.                 tempPicHand += qq;
  729.                 
  730.                 /* move the picture over, increase the handle by 1 */
  731.                 (*shortName)->numPicts++;
  732.                 HUnlock((*shortName)->pictHandle);
  733.                 MySetHandleSize((*shortName)->pictHandle, (GetHandleSize((*shortName)->pictHandle) + sizeof(Handle)));
  734.                 HLock((*shortName)->pictHandle);
  735.                 tempPicHand2 = (Handle *)*(*shortName)->pictHandle;
  736.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  737.                 *tempPicHand2 = *tempPicHand;
  738.                 /* move the rect over also */
  739.                 HUnlock((*shortName)->pictRects);
  740.                 MySetHandleSize((*shortName)->pictRects, (GetHandleSize((*shortName)->pictRects) + sizeof(Handle)));
  741.                 HLock((*shortName)->pictRects);
  742.                 tempPicHand2 = (Handle *)*(*shortName)->pictRects;
  743.                 tempPicHand2 += ((*shortName)->numPicts) - 1;
  744.                 *tempPicHand2 = *tempRectHand;
  745.                 HUnlock((*shortName)->pictRects);
  746.                 HUnlock((*shortName)->pictHandle);
  747.                 if ((qq + 1) != (*shortName)->numSubs) {
  748.                     register ii;                            /* need to move information down */
  749.                     for (ii = qq; ii < ((*shortName)->numSubs) - 1; ii++) {
  750.                         *tempPtr = *(tempPtr + 1);
  751.                         *tempRectHand = *(tempRectHand + 1);
  752.                         *tempPicHand = *(tempPicHand + 1);
  753.                         tempPtr += 1;
  754.                         tempRectHand += 1;
  755.                         tempPicHand += 1;
  756.                     }
  757.                 }
  758.                 (*shortName)->numSubs--;
  759.                 HUnlock((*shortName)->subs);
  760.                 MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) - sizeof(SectionHandle));
  761.                 HUnlock((*shortName)->subRects);
  762.                 MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) - sizeof(Handle)));
  763.                 
  764.             }
  765.         }
  766.     }
  767.     HUnlock((Handle)shortName);
  768.     /* and clear the highlight */
  769.     if (gShowPub || gShowSub) {
  770.         extern Rect gShowPubRect;
  771.         extern Rect gShowSubRect;
  772.         extern SectionHandle gShowingSecHandle;
  773.         gShowPub = gShowSub = false;
  774.         gShowingSecHandle = nil;
  775.         InvalRect(&gShowPubRect);
  776.         InvalRect(&gShowSubRect);
  777.     }
  778. }
  779.  
  780. /* end MyCancelSection */
  781.  
  782. void StoreSubscriber(windowCHandle shortName, SectionHandle secHandle, Handle inRect, Handle pictIn)
  783. {
  784.     OSErr myErr;
  785.     SectionHandle *tempPtr;
  786.     Handle *tempPicHand;
  787.     Size dataSize;
  788.     EditionRefNum sRefNum;
  789.     /* first we need to determine if this is a PICT or TEXT subscription, since I'm handling */
  790.     /* them differently for drill. */
  791.     myErr = OpenEdition(secHandle, &sRefNum);
  792.     if (myErr = EditionHasFormat(sRefNum, kGenericPICTWord, &dataSize))
  793.         (*secHandle)->refCon |= kTextType;
  794.     else
  795.         (*secHandle)->refCon |= kPictType;
  796.     /* Now that little mechanism could screw up, if the formats of the section have been */
  797.     /* changed since the subscription was originally created.  But it'll work here */
  798.     CloseEdition(sRefNum, true);
  799.     
  800.     /* increase our section handle holding handle by the size of a handle */
  801.     if (((*secHandle)->refCon & 0xf) == kPictType) {
  802.         HUnlock((*shortName)->subs);
  803.         MySetHandleSize((*shortName)->subs, GetHandleSize((*shortName)->subs) + sizeof(SectionHandle));
  804.         HLock((*shortName)->subs);
  805.         /* dereference the handle to our section handles in our window structure */
  806.         /* and cast it to a pointer to section handles, since that's what it contains */
  807.         tempPtr = (SectionHandle *)((*(*shortName)->subs) + (sizeof(SectionHandle) * ((*shortName)->numSubs)));
  808.         /* and store our subscriber section */
  809.         *tempPtr = (SectionHandle)secHandle;
  810.         HUnlock((*shortName)->subs);                        /* let it float again */
  811.         /* Here I'm setting up a handle for the picture data contained in the edition we just */
  812.         /* subscribed to, in an array of handles held in the handle subDataHandle  */
  813.         HUnlock((*shortName)->subDataHandle);
  814.         MySetHandleSize((*shortName)->subDataHandle, GetHandleSize((*shortName)->subDataHandle) + sizeof(Handle));  /* allocate */
  815.         HLock((*shortName)->subDataHandle);
  816.         /* deref it */
  817.         tempPicHand = (Handle *)*((*shortName)->subDataHandle);
  818.         tempPicHand += ((*shortName)->numSubs);
  819.         
  820.         if (pictIn == nil)
  821.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  822.         else
  823.             *tempPicHand = pictIn;
  824.         /* ••• NOTE:  You do _NOT_ read the data contained in this section yet! */
  825.         /* All you have done is subscribed to it, the Edition Manager has not told you */
  826.         /* that you can read it!  Wait for the section read event (see below) to get the */
  827.         /* data.  SO I store an empty handle here as a placeholder */
  828.         MoveHHi(*tempPicHand);
  829.         HUnlock((*shortName)->subRects);
  830.         MySetHandleSize((*shortName)->subRects, (GetHandleSize((*shortName)->subRects) + sizeof(Handle)));  /* allocate a new re*/
  831.         myErr = MemError();
  832.         if (myErr)
  833.             ShowMe("\pMemory error ", myErr, __LINE__);
  834.         HLock((*shortName)->subRects);
  835.         /* generate an empty display rectangle handle also */
  836.         tempPicHand = (Handle *)*((*shortName)->subRects);
  837.         tempPicHand += ((*shortName)->numSubs);
  838.         
  839.         if (inRect == nil)
  840.             *tempPicHand = NewHandle(0);                    /* set up a nil handleo */
  841.         else
  842.             *tempPicHand = inRect;
  843.         MoveHHi(*tempPicHand);
  844.         (*shortName)->numSubs++;                            /* increment our count of subscribers */
  845.         HUnlock((*shortName)->subRects);
  846.         HUnlock((*shortName)->subDataHandle);
  847.     } else {
  848.         if (((*secHandle)->refCon & 0xf) == kTextType) {        /* double checking here */
  849.             mySectionDataHandle newSection;
  850.             /* get a new text section record */
  851.             if (inRect == nil) {
  852.                 /* this means that it is being created fresh, so we have to get a */
  853.                 /* text section record from my routine */
  854.                 newSection = GetTextSection(shortName, stSubscriber);
  855.                 /* fill it with stuff relating to the section we just created */
  856.                 (*newSection)->publishing = false;
  857.                 (*newSection)->theID = (*secHandle)->sectionID;
  858.                 (*newSection)->theSection = secHandle;
  859.             } else {
  860.                 newSection = (mySectionDataHandle)inRect;
  861.             }
  862.             /* store it in our window structure */
  863.             if ((*shortName)->textSections) {
  864.                 mySectionDataHandle tempSection = (*shortName)->textSections;
  865.                 if ((*shortName)->textSections) {
  866.                     while ((*tempSection)->nextSection)
  867.                         tempSection = (*tempSection)->nextSection;
  868.                 }
  869.                 (*tempSection)->nextSection = newSection;
  870.                 
  871.             } else {
  872.                 /* first one */
  873.                 (*shortName)->textSections = newSection;
  874.             }
  875.         }
  876.     }
  877. }
  878.  
  879. pascal short SubExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
  880. {
  881. #pragma unused (yourDataPtr)
  882.     short myHit;
  883.     short itemType;
  884.     ControlHandle theButton;
  885.     Rect theRect;
  886.     /* first make sure that a sub-dialog is not frontmost */
  887.     /* so we don't filter keys or hits to a sub-dialog */
  888.     if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
  889.         /* first see if it's the 'first call' item (see the Standard File chapter).  If it is, then */
  890.         /* we preset our check box */
  891.         if (itemHit == -1) {
  892.             /* this gets the handle to our check box, since we know it's one past the last standard item */
  893.             GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  894.             SetControlValue(theButton, gResizeSub);             /* and set our current value */
  895.         } else {
  896.             /* only have one item in this expansion, but we'll check the range anyway to be safe */
  897.             myHit = itemHit - itemOffset;                   /* since our item numbers are relative to the total number */
  898.             /* of items in the dialog, and the system may change.  Always do your item numbering based */
  899.             /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
  900.             if (myHit == 1) {                               /* I only added one item, so this be the one */
  901.                 /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
  902.                 /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
  903.                 /* your custom items */
  904.                 GetDialogItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
  905.                 if (GetControlValue(theButton))
  906.                     gResizeSub = false;
  907.                 else
  908.                     gResizeSub = true;
  909.                 SetControlValue(theButton, gResizeSub);
  910.             }
  911.         }
  912.     }
  913.     return(itemHit);                                        /* the return value must be absolute */
  914. }
  915.  
  916. pascal Boolean SubExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
  917. {
  918. #pragma unused (itemHit,yourDataPtr) 
  919.     short itemType;
  920.     ControlHandle theButton;
  921.     Rect theRect;
  922.     /* first make sure that a sub-dialog is not frontmost */
  923.     /* so we don't filter keys or hits to a sub-dialog */
  924.     if (GetWRefCon((WindowPtr)theDialog) == sfMainDialogRefCon || GetWRefCon((WindowPtr)theDialog) == emOptionsDialogRefCon) {
  925.         /* standard filter proc kinda stuff here */
  926.         if ((theEvent->what) == keyDown) {
  927.             char tempChar;
  928.             tempChar = theEvent->message & charCodeMask;
  929.             
  930.             if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
  931.                 /* they pressed an A with the command key down, we get to handle it. */
  932.                 GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  933.                 if (GetControlValue(theButton))
  934.                     gResizeSub = false;
  935.                 else
  936.                     gResizeSub = true;
  937.                 SetControlValue(theButton, gResizeSub);
  938.                 return(true);                               /* tell folks we handled it */
  939.             }
  940.         }
  941.     }
  942.     return(false);                                          /* was not a keystroke we wanted */
  943.     
  944. }
  945.  
  946. /* DeleteSubscriber is called by a menu command 'Clear' */
  947.  
  948. void DeleteSubscriber(void)
  949. {
  950.     ModalFilterUPP upp = NewModalFilterProc(standardAlertFilter);
  951.     if (StopAlert(kCanxSub, upp) == 2) {
  952.         MyCancelSection(gShowingSecHandle, FindSection(gShowingSecHandle));
  953.         
  954.     }
  955.     DisposeRoutineDescriptor(upp);
  956. }
  957.  
  958. /* end DeleteSubscriber */
  959.  
  960. /* PasteSubscription pastes the section (a subscriber) from the clipboard into the */
  961. /* frontmost window (as you would expect) */
  962. void PasteSubscription(void)
  963. {
  964.     
  965.     windowCHandle tempWC;
  966.     SectionHandle tempHandle;
  967.     AliasHandle tempHandle2;
  968.     FSSpec newFileSpec;
  969.     Boolean myWasChanged;
  970.     Rect tempPRect =  {
  971.         0, 0, 40, 40
  972.     };
  973.     long myOffset;
  974.     long fred;
  975.     Handle tempRectHand = NewHandle(sizeof(Rect));
  976.     /* first see if there is a section handle on the clipboard */
  977.     /* kill the current section on the clipboard, if there is one */
  978.     /* •••• NEW, we're looking for section handles and aliases on the clipboard.  */
  979.     
  980.     /* set up a dummy picture for this incoming section.... */
  981.     if (!gScrapData)
  982.         gScrapData = NewHandle(0);
  983.     fred = GetScrap(gScrapData, rSectionType, &myOffset);
  984.     if (fred > 0) {                                         /* if there is a section on the clipboard */
  985.         myOffset = 0;
  986.         /* read in the rect also */
  987.         
  988.         fred = GetScrap(tempRectHand, kRECTType, &myOffset);
  989.         
  990.         if (fred > 0) {
  991.             short offH, offV;
  992.             /* move the rect to the upper left */
  993.             offH = (*(Rect *)*tempRectHand).right - (*(Rect *)*tempRectHand).left;
  994.             offV = (*(Rect *)*tempRectHand).bottom - (*(Rect *)*tempRectHand).top;
  995.             (*(Rect *)*tempRectHand).left = 0;
  996.             (*(Rect *)*tempRectHand).top = 0;
  997.             (*(Rect *)*tempRectHand).right = offH;
  998.             (*(Rect *)*tempRectHand).bottom = offV;
  999.             /* and read in the pict */
  1000.             myOffset = 0;
  1001.             GetScrap((Handle)gClipPict, kGenericPICTWord, &myOffset);
  1002.         } else {
  1003.             *(Rect *)*tempRectHand = tempPRect;             /* default it */
  1004.         }
  1005.     }
  1006.     HLock(tempRectHand);
  1007.     tempWC = (windowCHandle)GetWRefCon(FrontWindow());
  1008.     HLock((Handle)tempWC);
  1009.     if (gClipPict && GetHandleSize((Handle)gClipPict)) {
  1010.         InvalRect((Rect *)*tempRectHand);
  1011.         
  1012.     } else {
  1013.         *(Rect *)(*tempRectHand) = tempPRect;
  1014.     }
  1015.     /* update the ID of the section to include the master ID of the window yer pasting into */
  1016.     (*gClipSection)->sectionID += (*tempWC)->windowID;
  1017.     StoreSubscriber(tempWC, gClipSection, tempRectHand, (Handle)gClipPict);
  1018.     HUnlock((Handle)tempWC);
  1019.     /* Now, after you paste the subscription, you have to change the subscription on the clipboard. */
  1020.     /* You need to duplicate it, and assign a new ID number, since if the thing is pasted again */
  1021.     /* you could have two subscriptions with the same ID, which would not be nice.  So we do this... */
  1022.     tempHandle = gClipSection;
  1023.     tempHandle2 = (*gClipSection)->alias;
  1024.     HandToHand((Handle *)&tempHandle);
  1025.     HandToHand((Handle *)&tempHandle2);
  1026.     (*tempHandle)->sectionID = gSectionID;
  1027.     (*tempHandle)->alias = tempHandle2;
  1028.     gSectionID++;
  1029.     /* now register the section so the edition manager knows to send you updates */
  1030.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1031.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1032.         gClipSection = tempHandle;
  1033.     gClipHasContents = kClipHasSub;
  1034.     MyReadSection(tempHandle);
  1035.     
  1036. }
  1037. /* CutSubscription and CopySubscription move the current selection in the active window to the */
  1038. /* ClipBoard.  The main difference here from standard scrap handling is that the scrap you now */
  1039. /* have is dynamic.  The contents of the clipboard can change if the publisher of this subscription */
  1040. /* changes, so you must treat this section as you would any other subscriber */
  1041. /* frontmost window (as you would expect) */
  1042. void CutSubscription(void)
  1043. {
  1044.     CopySubscription();
  1045.     DeleteSubscriber();                                     /* even though they said cut, I want to make sure that they really mean it */
  1046. }
  1047. /* CopySubscriber moves the current display subscriber to the clipboard, making a new */
  1048. /* subscription in the process, since we don't want to have two copies of the same thing */
  1049. void CopySubscription(void)
  1050. {
  1051.     SectionHandle tempHandle;
  1052.     AliasHandle tempHandle2;
  1053.     FSSpec newFileSpec;
  1054.     Boolean myWasChanged;
  1055.     /* First check to see if there is already a section to remove */
  1056.     if (gClipHasContents == kClipHasSub) {
  1057.         KillClipSub();
  1058.     }
  1059.     tempHandle = gShowingSecHandle;
  1060.     /* copy the alias also */
  1061.     tempHandle2 = (*gShowingSecHandle)->alias;
  1062.     HandToHand((Handle *)&tempHandle);
  1063.     HandToHand((Handle *)&tempHandle2);
  1064.     /* create a unique ID for this section.  I'll just use the next section ID */
  1065.     (*tempHandle)->sectionID = gSectionID;
  1066.     (*tempHandle)->alias = tempHandle2;
  1067.     gSectionID++;
  1068.     /* now register the section so the edition manager knows to send you updates */
  1069.     ResolveAlias(nil, tempHandle2, &newFileSpec, &myWasChanged);
  1070.     if ((RegisterSection(&newFileSpec, tempHandle, &myWasChanged))==noErr)
  1071.         gClipSection = tempHandle;
  1072.     gClipPict = (PicHandle)NewHandle(0);                    /* allocate an empty handle for this picture data */
  1073.     gClipHasContents = kClipHasSub;
  1074.     /* write the section handle out to the cipboard */
  1075.     ZeroScrap();
  1076.     PutScrap(sizeof(Handle), rSectionType, (Ptr)&tempHandle);
  1077.     PutScrap(sizeof(Rect), kRECTType, (Ptr)&gShowSubRect);
  1078.     
  1079.     MyReadSection(tempHandle);
  1080.     
  1081.     InitCursor();                                           /* set to watch by MyReadSection, would normally be reset next pass */
  1082.     /* through the event loop, but NOT if it's being called by Cut, */
  1083.     /* so I'll reset it just to be safe */
  1084. }
  1085.  
  1086. OSErr ReadClipSection(Size readIn, EditionRefNum sRefNum)
  1087. {OSErr myErr = noErr;
  1088.     extern Handle gScrapData;
  1089.     MySetHandleSize((Handle)gClipPict, readIn);
  1090.     HLock((Handle)gClipPict);
  1091.     /* read the pict in */
  1092.     myErr = MyReadEditionData((Ptr)*gClipPict, kGenericPICTWord, sRefNum, &readIn);
  1093.     HUnlock((Handle)gClipPict);
  1094.     gScrapData = (Handle)gClipPict;
  1095.     if (((WindowPeek)FindClipWindow())->visible) {
  1096.         WindowPtr temp;
  1097.         GetPort(&temp);
  1098.         SetPort(FindClipWindow());
  1099.         InvalRect(&FindClipWindow()->portRect);
  1100.         SetPort(temp);
  1101.     }    
  1102. return(myErr);
  1103. }
  1104. /* This kills the current section on the clipboard, since it's being replaced */
  1105. /* and you don't want to receive events for it anymore */
  1106. void KillClipSub(void)
  1107. {
  1108.     UnRegisterSection(gClipSection);
  1109.     DisposeHandle((Handle)(*gClipSection)->alias);
  1110.     DisposeHandle((Handle)gClipSection);
  1111.     gClipSection = nil;
  1112.     gClipHasContents = kClipEmpty;
  1113.     if (GetHandleSize((Handle)gClipPict) != nil)
  1114.         KillPicture(gClipPict);
  1115. }
  1116.  
  1117. /* MyGoToPublisher is used if the user was holding down the Option key during a */
  1118. /* double click, to send them to the publisher without seeing the dialog box */
  1119. OSErr MyGoToPublisher(SectionHandle theSection)
  1120. {
  1121.     EditionInfoRecord theEdInfo;
  1122.     
  1123.     GetEditionInfo(theSection, &theEdInfo);
  1124.     return(GoToPublisherSection(&theEdInfo.container));
  1125. }
  1126.  
  1127. /* Searches the subcriber list, hilites the selection, and drags it */
  1128. /* This is very similar to the publisher check, but has added functionality */
  1129. /* for dragging the subscriber around the window */
  1130. Boolean SearchSubs(Point thePoint)
  1131. {
  1132.     register qq;
  1133.     Str63 pubString;
  1134.     Handle *theRectsHandle;
  1135.     Boolean subGotIt = false;
  1136.     windowCHandle shortname = (windowCHandle)GetWRefCon(FrontWindow());
  1137.     HLock((Handle)shortname);
  1138.     if ((*shortname)->numSubs) {                            /* does it have any subscribers? */
  1139.         HLock((*shortname)->subRects);                      /* lock down the rect handle */
  1140.         /* cast it as a pointer to handles for reading ease */
  1141.         theRectsHandle = (Handle *)*(*shortname)->subRects;
  1142.         for (qq = 0; qq < (*shortname)->numSubs; qq++) {        /* step through the subscribers */
  1143.             SectionHandle *tempPtr;
  1144.             Rect *checkRect;
  1145.             Rect cornerRect;
  1146.             HLock(*theRectsHandle);
  1147.             checkRect = (Rect *)**theRectsHandle;
  1148.             /* did they click in this rect? */
  1149.             InsetRect(checkRect, kNegFour, kNegFour);                   /* include the possible borders */
  1150.             if (PtInRect(thePoint, checkRect)) {            /* yes */
  1151.                 /* erase the old display rectangles, if there are any */
  1152.                 if (gShowSub){
  1153.                     InsetRect(&gShowSubRect, kNegFour, kNegFour);
  1154.                     InvalRect(&gShowSubRect);
  1155.                     InsetRect(&gShowSubRect, kFour, kFour);
  1156.  
  1157.                     }
  1158.                 gShowSub = true;
  1159.                 if (gShowPub) {
  1160.                     InvalRect(&gShowPubRect);
  1161.                     gShowPub = false;
  1162.                 }
  1163.                 /* get the section handle for this section */
  1164.                 HLock((*shortname)->subs);
  1165.                 tempPtr = (SectionHandle *)*(*shortname)->subs;
  1166.                 tempPtr += qq;
  1167.                 gShowingSecHandle = *tempPtr;
  1168.                 HUnlock((*shortname)->subs);
  1169.                 /* change the menu item name now */
  1170.                 GetIndString(pubString, kGeneralStrings, kSubOptString);
  1171.                 
  1172.                 SetMenuItemText(gEditMenuHandle, kSoptionsItem,pubString);
  1173.                 
  1174.                 InvalRect(checkRect);                       /* make sure it gets redrawn */
  1175.                 /* now I want the actual rect values so I can drag it around */
  1176.                 /* in response to the user */
  1177.                 gShowSubRect = *checkRect;
  1178.                 PenPat(&qd.dkGray);
  1179.                 PenSize(3, 3);
  1180.                 FrameRect(&gShowSubRect);
  1181.                 PenSize(1, 1);
  1182.                 /* Here you drag the thing around to where the user wants it, updating the 
  1183.                 *   window record as you do it. */
  1184.                 GetMouse(&thePoint);
  1185.                 InvalRect(&gShowSubRect);
  1186.                 /* two choices here.  They could be dragging the whole thing, or resizing it.  */
  1187.                 /* The resize box is in the lower right ten pixels, I'll say, so if the original */
  1188.                 /* click is there I'll go to the resize routine */
  1189.                 cornerRect = gShowSubRect;
  1190.                 cornerRect.top = cornerRect.bottom - 7;
  1191.                 cornerRect.left = cornerRect.right - 7;
  1192.                 if (PtInRect(thePoint, &cornerRect) && gResizeSub) {
  1193.                     
  1194.                     PullRect(shortname, &gShowSubRect, false, true,true);
  1195.                     
  1196.                 } else {
  1197.                     while (StillDown()) {                   /* keep doing it until they release the mouse */
  1198.                         Point tempPoint;
  1199.                          PenMode(patXor);
  1200.                          FrameRect(&gShowSubRect);           /* nasty way to put up a flashing border for the drag */
  1201.                          FrameRect(&gShowSubRect);
  1202.                         GetMouse(&tempPoint);
  1203.                         /* keep inside the window please, don't let them drag the */
  1204.                         /* rectangle outside the window bounds */
  1205.                         if (PtInRect(tempPoint, &(FrontWindow()->portRect))) {
  1206.                             if (tempPoint != thePoint) {
  1207.                                 OffsetRect(&gShowSubRect, tempPoint.h - thePoint.h, tempPoint.v - thePoint.v);
  1208.                                 thePoint = tempPoint;
  1209.                             }
  1210.                         }
  1211.                     }
  1212.                     PenMode(normal);
  1213.                 }
  1214.                 InvalRect(&gShowSubRect);
  1215.                 InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1216.                 InsetRect(&gShowSubRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1217.  
  1218.                 if (gShowSubRect != *checkRect) {           /* don't update if they didn't end up moving it */
  1219.  
  1220.  
  1221.                         *checkRect = gShowSubRect;          /* update our record of things */
  1222.                 }
  1223.  
  1224.                 
  1225.                 
  1226.                 subGotIt = true;
  1227.             } else {
  1228.             /* shrink it back agin */
  1229.             InsetRect(checkRect, kFour, kFour);                 /* remember that ShowingRect is kFour bigger */
  1230.  
  1231.             }
  1232.             HUnlock(*theRectsHandle);
  1233.             theRectsHandle += 1;                            /* increase by one Rect to check next */
  1234.             if (subGotIt)
  1235.                 break;
  1236.         }
  1237.         HUnlock((*shortname)->subRects);
  1238.     }
  1239.     HUnlock((Handle)shortname);
  1240.     return(subGotIt);
  1241. }
  1242.  
  1243. /* end SearchSubs */
  1244.  
  1245.  
  1246.  
  1247.  
  1248. #undef __SUBSCRIBE__
  1249.